use crate::data::Info10;
use crate::data::TickDatas;
use std::cmp;
use std::fmt::{Display, Result};

/// 账户信息
#[derive(Debug)]
pub struct Account {
    pub funds: isize,     // 账户中当前的资金
    stock_volume: usize,  // 账户中当前的股票
    last_buy_time: usize, // 上一次进行买入操作的时间
}
impl Display for Account {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result {
        write!(
            f,
            "funds: {}, stock:{}, last_buy_time:{}",
            self.funds, self.stock_volume, self.last_buy_time
        )
    }
}

impl Account {
    pub fn new() -> Account {
        Account {
            funds: 0,
            stock_volume: 0,
            last_buy_time: 0,
        }
    }
    // 进行市价委托买操作
    pub fn market_price_buy(&mut self, ask_info_10: &Info10, volumn: usize) {
        let mut res = volumn as isize;
        for x in 0..10 {
            res -= ask_info_10.info_1_vec[x].volume as isize;
            if res >= 0 {
                self.funds -= (ask_info_10.info_1_vec[x].price as isize)
                    * ask_info_10.info_1_vec[x].volume as isize;
            } else {
                self.funds -= (ask_info_10.info_1_vec[x].price as isize)
                    * (res + ask_info_10.info_1_vec[x].volume as isize);
                break;
            }
        }

        // 设置当前持有的股票总量
        self.stock_volume += volumn;
        self.last_buy_time = ask_info_10.time;
    }

    // 进行市价委托卖操作
    pub fn market_price_sell(&mut self, bid_info_10: &Info10, volumn: usize) {
        let mut res = volumn as isize;
        for x in 0..10 {
            res -= bid_info_10.info_1_vec[x].volume as isize;
            if res >= 0 {
                self.funds += (bid_info_10.info_1_vec[x].price as isize)
                    * bid_info_10.info_1_vec[x].volume as isize;
            } else {
                self.funds += (bid_info_10.info_1_vec[x].price as isize)
                    * (res + bid_info_10.info_1_vec[x].volume as isize);
                break;
            }
        }

        self.stock_volume -= volumn;
    }

    // 当前是否满足买入的时间限制
    pub fn satisfy_buy_time(&self, current: usize) -> bool {
        current as isize - self.last_buy_time as isize > 30_000_isize
    }

    // 进行被动单卖出操作, 返回30s之后剩余的股票数
    pub fn passive_sell(
        &mut self,
        ask_price: usize,
        volume: usize,
        time_ms: usize,
        tick_datas: &TickDatas,
    ) -> usize {
        let mut result = volume;
        let mut price = 0_usize;
        let bid_1_vec = tick_datas.get_bid_1_datas_in_30_seconds(time_ms);

        for bid_1 in bid_1_vec {
            if result <= 0 {
                break;
            }

            if bid_1.price >= ask_price {
                let sell_volume = cmp::min(bid_1.volume, result);
                result -= sell_volume;
                price += ask_price * sell_volume;
            }
        }

        // 卖出去赚的钱
        self.funds += price as isize;
        // 卖出去之后减少的股票量
        self.stock_volume -= volume - result;

        result
    }
}

/// 存储还没有进行卖出触发的股票
#[derive(Debug, PartialEq, Eq)]
pub struct BuyRecord {
    time: usize,   // 进行买入操作的时间
    volumn: usize, // 买入的量，当前所有的都为1000
}

/// 存储触发了卖出操作，但是还没有全量卖出去的股票
#[derive(Debug, PartialEq, Eq)]
pub struct SellRecord {
    time: usize,   // 卖出的时间
    volumn: usize, // 剩余的量
}

#[cfg(test)]
pub mod tests {
    use crate::data::{Info1, Info10};

    use super::Account;

    #[test]
    fn test_price_buy() {
        let mut account = Account::new();
        let ask_info_10 = Info10 {
            time: 93030000,
            info_1_vec: vec![
                Info1 {
                    price: 851800_usize,
                    volume: 300_usize,
                },
                Info1 {
                    price: 852000_usize,
                    volume: 400_usize,
                },
                Info1 {
                    price: 853000_usize,
                    volume: 200_usize,
                },
                Info1 {
                    price: 853700_usize,
                    volume: 300_usize,
                },
                Info1 {
                    price: 853900_usize,
                    volume: 500_usize,
                },
                Info1 {
                    price: 854800_usize,
                    volume: 300_usize,
                },
                Info1 {
                    price: 854900_usize,
                    volume: 100_usize,
                },
                Info1 {
                    price: 855000_usize,
                    volume: 6100_usize,
                },
                Info1 {
                    price: 855800_usize,
                    volume: 300_usize,
                },
                Info1 {
                    price: 856000_usize,
                    volume: 100_usize,
                },
            ],
        };
        account.market_price_buy(&ask_info_10, 1000);

        assert_eq!(
            account.funds,
            0_isize - (851800 * 300 + 852000 * 400 + 853000 * 200 + 853700 * 100) as isize
        );
        assert_eq!(account.stock_volume, 1000);
        assert_eq!(account.last_buy_time, 93030000);
    }

    #[test]
    pub fn test_passive_sell() {
        use crate::data::TickDatas;
        let mut account = Account::new();
        account.stock_volume = 200000;
        let ask_price = 907100_usize;
        let volume = 1000_usize;
        let time = 101019000_usize;
        let tick_datas = TickDatas::new().unwrap();

        let res = account.passive_sell(ask_price, volume, time, &tick_datas);

        assert_eq!(res, 0);
        assert_eq!(account.funds as usize, ask_price * 1000_usize);
        assert_eq!(account.stock_volume, 200000 - 1000);
    }
}
